﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Collections.Concurrent;

namespace Inovout.Descriptors
{
    public class EnumDescriptor : MemberDescriptor, ITypeDescriptor
    {
        #region Private Field
        /// <summary>
        /// 枚举声明类型
        /// </summary>
        private Type enumType;
        /// <summary>
        /// 枚举项集合
        /// </summary>
        private Dictionary<Enum, EnumItemDescriptor> enumDictionary;
        /// <summary>
        /// 标记
        /// </summary>
        private bool flag;

        #endregion

        #region Property

        public EnumItemDescriptor[] EnumItems
        {
            get { return enumDictionary.Values.ToArray(); }
        }

        /// <summary>
        /// 是否有多个特性标记
        /// </summary>
        public bool Flag
        {
            get
            {
                return flag;
            }
        }

        #endregion

        #region Indexr

        /// <summary>
        /// 根据枚举获取描述
        /// </summary>
        /// <param name="item"></param>
        /// <returns>描述</returns>
        internal EnumItemDescriptor this[Enum item]
        {
            get
            {
                return enumDictionary[item];
            }
        }
        public EnumItemDescriptor GetEnumItem(int enumValue)
        {
            return this[enumValue];
        }
        public EnumItemDescriptor this[string enumName]
        {
            get
            {
                return enumDictionary[(Enum)Enum.Parse(enumType, enumName)];
            }
        }

        public EnumItemDescriptor this[int enumValue]
        {
            get
            {
                return this[(Enum)Enum.ToObject(enumType, enumValue)];
            }
        }

        #endregion

        #region Constructor

        /// <summary>
        /// 初始化 EnumDictionary类的新实例。
        /// </summary>
        /// <param name="enumType">枚举声明类型</param>
        public EnumDescriptor(Type enumType)
            : base(enumType)
        {
            ArgumentAssert.IsEnumType(enumType, "enumType");

            FieldInfo[] fieldInfos = enumType.GetFields(BindingFlags.Public | BindingFlags.Static);
            ArgumentAssert.IsNotNull(fieldInfos, "enumType");


            this.enumType = enumType;
            flag = enumType.IsDefined(typeof(FlagsAttribute), false);
            enumDictionary = new Dictionary<Enum, EnumItemDescriptor>(fieldInfos.Length);

            foreach (FieldInfo fieldInfo in fieldInfos)
            {
                EnumItemDescriptor enumItemDescriptor = new EnumItemDescriptor(fieldInfo);
                enumDictionary.Add(enumItemDescriptor.Value, enumItemDescriptor);
            }
        }

        #endregion

        #region Method
        private static readonly IDictionary<Type, EnumDescriptor> enumDescriptors = new ConcurrentDictionary<Type, EnumDescriptor>();
        public static EnumDescriptor Create(Type enumType)
        {
            ArgumentAssert.IsEnumType(enumType,"enumType");
            EnumDescriptor enumDescriptor=null;
            if(!enumDescriptors.TryGetValue(enumType,out enumDescriptor))
            {
                enumDescriptor= new EnumDescriptor(enumType);
                enumDescriptors.Add(enumType,enumDescriptor);
            }
            return enumDescriptor;
        }

        #endregion


        public static EnumDescriptor Create<TEnumType>()
        {
            return Create(typeof(TEnumType));
        }

        public Enum GetEnum(string value)
        {
            return (this[value].Value);
        }
    }
}
